package com.zensun.system.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zensun.common.annotation.DataScope;
import com.zensun.common.constant.Constants;
import com.zensun.common.constant.UserConstants;
import com.zensun.common.core.redis.RedisCache;
import com.zensun.common.enums.domain.SysDeptEnum;
import com.zensun.common.enums.domain.SysUserEnum;
import com.zensun.common.utils.Assert;
import com.zensun.system.domain.*;
import com.zensun.system.domain.dto.SysProfilePatchDto;
import com.zensun.system.domain.dto.SysUserDto;
import com.zensun.system.domain.dto.SysUserPatchDto;
import com.zensun.system.domain.model.LoginUser;
import com.zensun.system.domain.vo.SysUserDetailVo;
import com.zensun.system.domain.vo.SysUserVo;
import com.zensun.system.mapper.SysDeptMapper;
import com.zensun.system.mapper.SysRoleMapper;
import com.zensun.system.mapper.SysUserMapper;
import com.zensun.system.mapper.SysUserRoleMapper;
import com.zensun.system.service.ISysUserService;
import com.zensun.system.util.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户 业务层处理
 *
 * @author gmk
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SysDeptMapper deptMapper;

    /**
     * 根据条件分页查询用户列表
     *
     * @param userDto 用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUserVo> selectUserList(SysUserDto userDto) {
        return userMapper.selectUserList(userDto);
    }

    @Override
    public SysUserDetailVo selectUserById(Long userId) {
        SysUserDetailVo sysUserDetailVo = new SysUserDetailVo();
        SysUser byId = this.getById(userId);
        //查询此用户所拥有的角色
        LambdaQueryWrapper<SysUserRole> q = new LambdaQueryWrapper<SysUserRole>();
        q.eq(SysUserRole::getUserId, userId);
        List<SysUserRole> sysUserRoles = userRoleMapper.selectList(q);
        List<Long> roldIds = CollStreamUtil.toList(sysUserRoles, SysUserRole::getRoleId);
        BeanUtils.copyProperties(byId, sysUserDetailVo);
        sysUserDetailVo.setRoleIds(UserConstants.ADMIN_ID.equals(userId) ? Arrays.asList(UserConstants.ADMIN_ID) : roldIds);
        return sysUserDetailVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertUser(SysUser user) {


        //准备数据
        // 3.插入数据
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        SysDept sysDept = deptMapper.selectById(user.getDeptId());
        //4.用户类型
        String userType = SysDeptEnum.Type.PROJECT.getCode().equals(sysDept.getType()) ? SysUserEnum.UserType.PROJECT.getCode() : SysUserEnum.UserType.SYSTEM.getCode();
        user.setUserType(userType);

        if (user.getSelectNew() == null) {
            //一.数据库不存在此条数据 普通的新增

            // 2.校验手机号是否存在
            Assert.isTrue(!checkPhoneUnique(user), "新增用户'" + user.getUserName() + "'失败，手机号码已存在");
            userMapper.insert(user);
        } else if (user.getSelectNew()) {
            //二.数据库存在此条数据  启用新用户
            Long userId = userMapper.selectUserByPhoneDelete(user.getTelephone());
            SysUser s = new SysUser();
            s.setUserId(userId);
            s.setTelephone(user.getTelephone() + "-");
            userMapper.updateTelePhoneGang(s);
            userMapper.insert(user);
        } else {
            //三.数据库存在此条数据  启用历史数据
            Long userId = userMapper.selectUserByPhoneDelete(user.getTelephone());
            user.setUserId(userId);
            user.setIsDelete(0);
            user.setStatus(UserConstants.NORMAL);
            user.setUpdateBy(SecurityUtils.getLoginUser().getUser().getUserId());
            userMapper.updateSysUserById(user);
        }

        //5.增加的角色Ids
        Long[] roleIds = user.getRoleIds();
        //构建增加的角色
        List<SysUserRole> sysUserRolesParam = CollStreamUtil.toList(Arrays.asList(roleIds), i -> {
            SysUserRole s = new SysUserRole();
            s.setRoleId(i);
            s.setUserId(user.getUserId());
            return s;
        });
        userRoleMapper.insertBatch(sysUserRolesParam);

        return 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateUser(SysUser user) {
        String userName = user.getUserName();
        // 1.校验
        checkUserAllowed(user.getUserId());
        //2.先删除所有的角色
        LambdaQueryWrapper<SysUserRole> q = new LambdaQueryWrapper<>();
        q.eq(SysUserRole::getUserId, user.getUserId());
        userRoleMapper.delete(q);
        //3.增加的角色Ids
        Long[] roleIds = user.getRoleIds();
        //构建增加的角色
        List<SysUserRole> sysUserRolesParam = CollStreamUtil.toList(Arrays.asList(roleIds), i -> {
            SysUserRole s = new SysUserRole();
            s.setRoleId(i);
            s.setUserId(user.getUserId());
            return s;
        });
        userRoleMapper.insertBatch(sysUserRolesParam);
        //4.用户类型
        SysDept sysDept = deptMapper.selectById(user.getDeptId());
        String userType = SysDeptEnum.Type.PROJECT.getCode().equals(sysDept.getType()) ? SysUserEnum.UserType.PROJECT.getCode() : SysUserEnum.UserType.SYSTEM.getCode();
        user.setUserType(userType);

        // 5.更新数据
        return userMapper.updateById(user);
    }

    /**
     * 检测手机号是否唯一
     *
     * @param user
     * @return
     */
    private boolean checkPhoneUnique(SysUser user) {
        String telephone = user.getTelephone();
        LambdaQueryWrapper<SysUser> q = new LambdaQueryWrapper<>();
        q.eq(SysUser::getTelephone, telephone);
        int count = this.count(q);
        return count > 0 ? false : true;
    }

    /**
     * 查询用户所属角色组
     *
     * @param userId 手机号
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(Long userId) {

        if (UserConstants.ADMIN_ID.equals(userId)) {
            return UserConstants.ADMIN_NICKNAME;
        }
        LambdaQueryWrapper<SysUserRole> ur = new LambdaQueryWrapper<SysUserRole>();
        ur.eq(SysUserRole::getUserId, userId);
        List<Long> roleIds = CollStreamUtil.toList(userRoleMapper.selectList(ur), SysUserRole::getRoleId);
        //userMapper
        LambdaQueryWrapper<SysRole> q = new LambdaQueryWrapper<>();
        q.in(SysRole::getRoleId, roleIds);
        List<SysRole> sysRoles = roleMapper.selectList(q);
        return sysRoles.stream()
                .map(SysRole::getRoleName)
                .collect(Collectors.joining(","));
    }

    /**
     * 校验用户是否允许操作
     *
     * @param userId 用户Ids
     */
    public void checkUserAllowed(Long userId) {
        Assert.isTrue(ObjectUtil.isNotNull(userId) && UserConstants.ADMIN_ID.equals(userId), "不允许操作超级管理员用户");
    }

    /**
     * 修改用户基本信息
     *
     * @param sysProfilePatchDto 用户信息
     * @return 结果
     */
    @Override
    public int updateUserProfile(SysProfilePatchDto sysProfilePatchDto) {
        Assert.isTrue(UserConstants.ADMIN_USENAME.equals(sysProfilePatchDto.getUserName()), "修改用户'" + sysProfilePatchDto.getUserName() + "'失败");
        SysUser sysUser = new SysUser();
        sysUser.setUserId(sysProfilePatchDto.getUserId());
        sysUser.setUserName(sysProfilePatchDto.getUserName());
        return userMapper.updateById(sysUser);
    }

    /**
     * 修改用户头像
     *
     * @param telephone 用户名
     * @param avatar    头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(String telephone, String avatar) {
        SysUser user = new SysUser();
        user.setAvatar(avatar);
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<SysUser>();
        updateWrapper.eq("telephone", telephone);
        return userMapper.update(user, updateWrapper) > 0 ? true : false;
    }

    /**
     * 重置用户密码
     *
     * @param sysUserPatchDto 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(SysUserPatchDto sysUserPatchDto) {
        SysUser user = new SysUser();
        user.setUserId(sysUserPatchDto.getUserId());
        checkUserAllowed(sysUserPatchDto.getUserId());
        Assert.isPassword(sysUserPatchDto.getPassword(), "密码应该由大小写字母、数字、符号@$!%*#_~?&组成");
        user.setPassword(SecurityUtils.encryptPassword(sysUserPatchDto.getPassword()));
        return userMapper.updateById(user);
    }

    /**
     * 重置用户密码
     *
     * @param userId   用户Id
     * @param password 密码
     * @return 结果
     */
    @Override
    public int resetUserPwd(Long userId, String password) {
        SysUser user = new SysUser();
        user.setPassword(password);
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<SysUser>();
        updateWrapper.eq("user_id", userId);
        return userMapper.update(user, updateWrapper);
    }


    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional
    public boolean deleteUserByIds(Long[] userIds) {

        // 1.校验
        Assert.isEmpty(Arrays.asList(userIds), "请选择用户");
        for (Long userId : userIds) {
            Assert.isTrue(SecurityUtils.getLoginUser().getUser().getUserId().equals(userId), "不允许删除自己");
            checkUserAllowed(userId);
        }
        // 2.删除SysUserRole中间表
        LambdaQueryWrapper<SysUserRole> q = new LambdaQueryWrapper<>();
        q.in(SysUserRole::getUserId, userIds);
        userRoleMapper.delete(q);
        // 3.删除的用户清除redis
        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
        for (Long userId : userIds) {
            for (String key : keys) {
                Object userStr = redisCache.getCacheObject(key);
                LoginUser user = (LoginUser) userStr;
                if (userId.equals(user.getUser().getUserId())) {
                    //如果删除的用户在线的话 直接强退用户
                    redisCache.deleteObject(key);
                }
            }
        }
        //4.删除sysuser表
        return baseMapper.deleteBatchIds(Arrays.asList(userIds)) > 0 ? true : false;
    }

    @Override
    public SysUser selectUserByTelePhone(String telephone) {
        LambdaQueryWrapper<SysUser> q = new LambdaQueryWrapper<SysUser>();
        q.eq(SysUser::getTelephone, telephone);
        SysUser sysUser = userMapper.selectOne(q);

        Assert.isNull(sysUser, "登录用户：" + telephone + " 不存在");
        Assert.isTrue(UserConstants.EXCEPTION.equals(sysUser.getStatus()), "对不起，您的账号：" + telephone + " 已停用");

        //查询用户角色中间表  查询出来roleIds
        LambdaQueryWrapper<SysUserRole> ur = new LambdaQueryWrapper<SysUserRole>();
        ur.eq(SysUserRole::getUserId, sysUser.getUserId());
        List<SysUserRole> sysUserRoles = userRoleMapper.selectList(ur);
        if (!CollectionUtils.isEmpty(sysUserRoles)) {
            List<Long> roleIds = CollStreamUtil.toList(sysUserRoles, SysUserRole::getRoleId);
            //角色
            LambdaQueryWrapper<SysRole> r = new LambdaQueryWrapper<SysRole>();
            r.in(SysRole::getRoleId, roleIds);
            List<SysRole> sysRoles = roleMapper.selectList(r);
            sysUser.setRoles(sysRoles);
        }
        if (sysUser.getDeptId() != null) {
            //部门
            LambdaQueryWrapper<SysDept> d = new LambdaQueryWrapper<SysDept>();
            d.eq(SysDept::getDeptId, sysUser.getDeptId());
            SysDept sysDept = deptMapper.selectOne(d);
            sysUser.setDept(sysDept);
        }
        return sysUser;
    }

    @Override
    public boolean addVerify(String telePhone) {
        //1.2校验手机号是否和已删除的手机号相同
        Long count = baseMapper.selectUserByPhoneDelete(telePhone);
        return count != null && count > 0;
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户姓名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserName(String userName) {
        LambdaQueryWrapper<SysUser> q = new LambdaQueryWrapper<SysUser>();
        q.eq(SysUser::getUserName, userName);
        SysUser sysUser = userMapper.selectOne(q);

        //查询admin的角色
        LambdaQueryWrapper<SysRole> r = new LambdaQueryWrapper<SysRole>();
        r.in(SysRole::getRoleId, UserConstants.ADMIN_ID);
        List<SysRole> sysRoles = roleMapper.selectList(r);
        sysUser.setRoles(sysRoles);
        if (sysUser.getDeptId() != null) {
            //部门
            LambdaQueryWrapper<SysDept> d = new LambdaQueryWrapper<SysDept>();
            d.eq(SysDept::getDeptId, sysUser.getDeptId());
            SysDept sysDept = deptMapper.selectOne(d);
            sysUser.setDept(sysDept);
        }

        return sysUser;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean blockedAccount(UpdateUserStatus updateUserStatus) {
        // 1.准备数据
        List<Long> userIds = updateUserStatus.getUserIds();
        // 2.校验
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<SysUser>();
        queryWrapper.eq(SysUser::getStatus, SysUserEnum.Status.NORMAL.getCode());
        List<Long> normalIdsList = this.list(queryWrapper).stream().map(SysUser::getUserId).collect(Collectors.toList());
        Assert.isContainsAll(normalIdsList, updateUserStatus.getUserIds(), "请选择状态为正常的用户！");
        //3.修改用户状态
        List<SysUser> userList = new ArrayList<>();
        for (int i = 0; i < userIds.size(); i++) {
            Long userId = userIds.get(i);
            SysUser user = new SysUser();
            user.setStatus(SysUserEnum.Status.UNNORMAL.getCode());
            user.setUserId(userId);
            userList.add(user);
        }
        //3批量增加解冻操作记录
        return this.updateBatchById(userList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean dredgeAccount(UpdateUserStatus updateUserStatus) {

        // 1.准备数据
        List<Long> userIds = updateUserStatus.getUserIds();
        // 2.校验
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<SysUser>();
        queryWrapper.eq(SysUser::getStatus, SysUserEnum.Status.UNNORMAL.getCode());
        List<Long> normalIdsList = this.list(queryWrapper).stream().map(SysUser::getUserId).collect(Collectors.toList());
        Assert.isContainsAll(normalIdsList, updateUserStatus.getUserIds(), "请选择状态为异常的用户！");
        //3.修改用户状态
        List<SysUser> userList = new ArrayList<>();
        for (int i = 0; i < userIds.size(); i++) {
            Long userId = userIds.get(i);
            SysUser user = new SysUser();
            user.setStatus(SysUserEnum.Status.NORMAL.getCode());
            user.setUserId(userId);
            userList.add(user);
        }
        //3批量增加解冻操作记录
        return this.updateBatchById(userList);
    }
}
